﻿using RabbitMQ.Client;
using System;
using System.Text;
using System.Threading.Tasks;
using Maltose.Log;
using System.Collections.Generic;

namespace Maltose.MessageQueue.Publish
{
    /// <summary>
    /// 消息队列发送信息
    /// </summary>
    public class MessageQueuePublish : MessageQueueHostConfig
    {
        /// <summary>
        /// 连接配置信息
        /// </summary>
        ConnectionFactory factory;

        /// <summary>
        /// 消息队列发送信息
        /// </summary>
        public MessageQueuePublish()
        {
            factory = new ConnectionFactory()
            {
                HostName = HostName,
                Port = Port,
                UserName = UserName,
                Password = Password
            };
        }

        /// <summary>
        /// 发送队列消息 
        /// </summary>
        /// <param name="queueName">队列名称</param>
        /// <param name="content">消息内容</param>
        /// <param name="arguments">额外参数</param>
        /// <returns></returns>
        public bool SendQueueMessage(string queueName, string content, Dictionary<string, object> arguments = null)
        {
            try
            {
                using (var connection = factory.CreateConnection())
                {
                    using (var channel = connection.CreateModel())
                    {
                        channel.QueueDeclare(queueName, true, false, false, arguments);

                        //消息持久化
                        var properties = channel.CreateBasicProperties();
                        properties.Persistent = true;

                        var body = Encoding.UTF8.GetBytes(content);

                        //发送
                        channel.BasicPublish(exchange: "",
                            routingKey: queueName,
                            basicProperties: properties, body: body);

                        return true;
                    }
                }
            }
            catch (Exception e)
            {
                UseLog.Debug($"消息队列发送错误[{queueName}]", "消息队列发送", e);
                return false;
            }
        }

        /// <summary>
        /// 发送队列消息 对象自动转换成JSON格式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="queueName">队列名称</param>
        /// <param name="content"></param>
        /// <param name="arguments">额外参数</param>
        /// <returns></returns>
        public bool SendQueueMessage<T>(string queueName, T content, Dictionary<string, object> arguments = null)
        {
            return SendQueueMessage(queueName, content.ToJson(), arguments);
        }

        /// <summary>
        /// 发送延迟队列消息 基于rabbitmq_delayed_message_exchange 插件实现
        /// </summary>
        /// <param name="queueName">队列名称</param>
        /// <param name="content">消息内容</param>
        /// <param name="delayTime">延迟时间 毫秒计算</param>
        /// <returns></returns>
        public bool SendDelayQueueMessage(string queueName, string content, int delayTime)
        {
            var headers = new Dictionary<string, object>();
            headers.Add("x-delay", delayTime);

            var arguments = new Dictionary<string, object>();
            arguments.Add("x-delayed-type", "direct");

            using (var connection = factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.ExchangeDeclare(queueName, "x-delayed-message", true, false, arguments);

                    //消息持久化
                    var properties = channel.CreateBasicProperties();
                    properties.Persistent = true;
                    properties.Headers = headers;

                    var body = Encoding.UTF8.GetBytes(content);

                    //发送
                    channel.BasicPublish(exchange: queueName,
                        routingKey: "",
                        basicProperties: properties, body: body);

                    return true;
                }
            }
        }

        /// <summary>
        /// 发送延迟队列消息,对象自动转移成JSON字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="queueName"></param>
        /// <param name="content"></param>
        /// <param name="delayTime"></param>
        /// <returns></returns>
        public bool SendDelayQueueMessage<T>(string queueName, T content, int delayTime)
        {
            return SendDelayQueueMessage(queueName, content.ToJson(), delayTime);
        }


        /// <summary>
        /// 发送交换通道消息
        /// </summary>
        /// <param name="exchange">通道</param>
        /// <param name="content">内容</param>
        /// <param name="routingKey">路由</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public bool SendExchangesMessage(string exchange, string content, string routingKey = "", ExchangePublishType type = ExchangePublishType.Topic)
        {
            try
            {
                using (var connection = factory.CreateConnection())
                {
                    using (var channel = connection.CreateModel())
                    {

                        channel.ExchangeDeclare(exchange, type.ToEnumDescription(), true);

                        //消息持久化
                        var properties = channel.CreateBasicProperties();
                        properties.Persistent = true;

                        var body = Encoding.UTF8.GetBytes(content);

                        //发送
                        channel.BasicPublish(exchange, routingKey, properties, body);
                        return true;
                    }
                }
            }
            catch (Exception e)
            {
                UseLog.Debug($"消息队列发送错误[{exchange}]", "消息队列发送", e);
                return false;
            }
        }

        /// <summary>
        /// 发送通道消息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="exchange">通道</param>
        /// <param name="content">内容</param>
        /// <param name="routingKey">路由</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public bool SendExchangesMessage<T>(string exchange, T content, string routingKey = "", ExchangePublishType type = ExchangePublishType.Topic) 
        {
            return SendExchangesMessage(exchange, content.ToJson(), routingKey, type);
        }
    }

}
